<?xml version="1.0" ?>
<!-- This is part of the "system configuration" -->
<!-- This will not need to be changed on an application-by-application basis -->

<PatternConfig>

  <!-- Loop optimizations make loops-of-loops more efficient -->
  <!-- Rule #1: The what="..." part must have exactly one char after 'x' and before ')' -->
  <!--    Consequence: no optimizations where dumb begins "(?:x{n,m})" -->
  <!-- Rule #2: The replacement part must begin with a single character such as 'x' -->
  <!--    Consequence: no optimizations that result in things of the form "(?:___)" -->
  <!-- Rule #3: Only 1-char loop-bodies (with optional preceding '\\') are optimized. -->
  <!--    Consequence: the optimization won't make things like "((xy)+)+" any faster. -->
  <LoopOptimization what="(?:x+)?">x*</LoopOptimization>
  <LoopOptimization what="(?:x+)*">x*</LoopOptimization>
  <LoopOptimization what="(?:x+)+">x+</LoopOptimization>
  <LoopOptimization what="(?:x?)?">x?</LoopOptimization>
  <LoopOptimization what="(?:x?)*">x*</LoopOptimization>
  <LoopOptimization what="(?:x?)+">x*</LoopOptimization>
  <LoopOptimization what="(?:x*)?">x*</LoopOptimization>
  <LoopOptimization what="(?:x*)*">x*</LoopOptimization>
  <LoopOptimization what="(?:x*)+">x*</LoopOptimization>

  <!-- Composite keywords have a "pre-regexp" and an "post-regexp" -->
  <Composite name="optional "                 pre=""    post="?"      child="atom" result="seq" />
  <Composite name="lazy optional "            pre=""    post="??"     child="atom" result="seq" />
  <Composite name="(\d+)\+ "                  pre=""    post="{n,}"   child="atom" result="seq" />
  <Composite name="lazy (\d+)\+ "             pre=""    post="{n,}?"  child="atom" result="seq" />
  <Composite name="(\d+)-(\d+) "              pre=""    post="{n,m}"  child="atom" result="seq" />
  <Composite name="lazy (\d+)-(\d+) "         pre=""    post="{n,m}?" child="atom" result="seq" />
  <Composite name="(\d+) "                    pre=""    post="{n}"    child="atom" result="seq" />
  <Composite name="lazy (\d+) "               pre=""    post="{n}?"   child="atom" result="seq" />
  <Composite name="oneof ([^{}]+)"            pre="["   post="]"      child="none" result="atom"/>
  <Composite name="not-oneof ([^{}]+)"        pre="[^"  post="]"      child="any"  result="atom"/>
  <Composite name="group "                    pre="(?:" post=")"      child="any"  result="atom"/>
  <Composite name="peek "                     pre="(?=" post=")"      child="any"  result="atom"/>
  <Composite name="peek-not "                 pre="(?!" post=")"      child="any"  result="atom"/>
  <Composite name="not "                      pre="(?!" post=")."     child="any"  result="seq" />
  <Composite name="raw-atom(.)(.*?)\1"        pre=""    post="regexp" child="none" result="atom"/>
  <Composite name="raw-sequence(.)(.*?)\1"    pre=""    post="regexp" child="none" result="seq" />
  <Composite name="raw-alternation(.)(.*?)\1" pre=""    post="regexp" child="none" result="alt" />

  <!-- Back-references -->
  <Composite name="ditto-memo-1"              pre="\1"  post=""       child="none" result="seq" />
  <Composite name="ditto-memo-2"              pre="\2"  post=""       child="none" result="seq" />
  <Composite name="ditto-memo-3"              pre="\3"  post=""       child="none" result="seq" />
  <Composite name="ditto-memo-4"              pre="\4"  post=""       child="none" result="seq" />
  <Composite name="ditto-memo-5"              pre="\5"  post=""       child="none" result="seq" />
  <Composite name="ditto-memo-6"              pre="\6"  post=""       child="none" result="seq" />
  <Composite name="ditto-memo-7"              pre="\7"  post=""       child="none" result="seq" />
  <Composite name="ditto-memo-8"              pre="\8"  post=""       child="none" result="seq" />
  <Composite name="ditto-memo-9"              pre="\9"  post=""       child="none" result="seq" />

  <!-- Keywords that don't consume any characters ("assertions") -->
  <Keyword name="{caseinsensitive}"       extra="false">{raw-sequence_(?i)(?:)_}</Keyword>
  <Keyword name="{peek-wordboundary}"     extra="false">{raw-sequence_\b_}</Keyword>
  <Keyword name="{peek-not-wordboundary}" extra="false">{raw-sequence_\B_}</Keyword>
  <Keyword name="{peek-beginstring}"      extra="false">{raw-sequence_\A_}</Keyword>
  <Keyword name="{peek-endstring}"        extra="false">{raw-sequence_\Z_}</Keyword>

  <!-- Keywords that translate to low-level Perl5-special characters -->
  <Keyword name="{bar}"                >{raw-atom_\|_}</Keyword>
  <Keyword name="{letter{bar}digit{bar}_}"    >{raw-atom_\w_}</Keyword>
  <Keyword name="{not-letter{bar}digit{bar}_}">{raw-atom_\W_}</Keyword>
  <Keyword name="{anychar}"            >{raw-atom_._}</Keyword>
  <Keyword name="{digit}"              >{raw-atom_\d_}</Keyword>
  <Keyword name="{not-digit}"          >{raw-atom_\D_}</Keyword>
  <Keyword name="{formfeed}"           >{raw-atom_\f_}</Keyword>
  <Keyword name="{gt}"                 >{raw-atom_\>_}</Keyword>
  <Keyword name="{lbrace}"             >{raw-atom_\{_}</Keyword>
  <Keyword name="{lparen}"             >{raw-atom_\(_}</Keyword>
  <Keyword name="{lt}"       HACK="{raw-atom_\&lt;_}"></Keyword>
  <Keyword name="{newline}"            >{raw-atom_\n_}</Keyword>
  <Keyword name="{null}"               >{raw-atom_\0_}</Keyword>
  <Keyword name="{rbrace}"             >{raw-atom_\}_}</Keyword>
  <Keyword name="{return}"             >{raw-atom_\r_}</Keyword>
  <Keyword name="{rparen}"             >{raw-atom_\)_}</Keyword>
  <Keyword name="{tab}"                >{raw-atom_\t_}</Keyword>
  <Keyword name="{whitespace-char}"    >{raw-atom_\s_}</Keyword>
  <Keyword name="{not-whitespace-char}">{raw-atom_\S_}</Keyword>
  <Keyword name="{starts-with}"        >{raw-atom_^_}</Keyword>

  <!-- Generic/convenience keywords -->
  <Keyword name="{space}"       > </Keyword>
  <Keyword name="{ws}"          >{whitespace-chars}</Keyword>
  <Keyword name="{semicolon}"   >;</Keyword>
  <Keyword name="{sign}"        >{oneof +-}</Keyword>
  <Keyword name="{letter}"      >{oneof abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ}</Keyword>
  <Keyword name="{letter{bar}_}"    >{oneof abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_}</Keyword>
  <Keyword name="{letter{bar}digit}">{oneof abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789}</Keyword>
  <Keyword name="{lowercase-letter}">{oneof abcdefghijklmnopqrstuvwxyz}</Keyword>
  <Keyword name="{uppercase-letter}">{oneof ABCDEFGHIJKLMNOPQRSTUVWXYZ}</Keyword>
  <Keyword name="{capital-letter}">{oneof ABCDEFGHIJKLMNOPQRSTUVWXYZ}</Keyword>

  <!-- {zip5} matches exactly 5 digits; e.g., "12345". -->
  <Keyword name="{zip5}">{5 {digit}}</Keyword>

  <!-- {zip5+4} matches 5 digits, a '-', then 4 more digits; e.g., "12345-1234". -->
  <Keyword name="{zip5+4}">{5 {digit}}-{4 {digit}}</Keyword>

  <!-- {zip5+opt4} matches either {zip5} or {zip5+4}: the "+4" part is optional. -->
  <!-- Group #1 matches the {zip5} part; group #2 matches the 4 digits of the "+4" part (if present) -->
  <Keyword name="{zip5+opt4}">({5 {digit}}){optional -({4 {digit}})}</Keyword>

  <!-- {identifier} matches an identifier: a {letter|_} then 0+ {letter|digit|_} -->
  <Keyword name="{identifier}">{letter|_}{0+ {letter|digit|_}}</Keyword>

  <!-- {word} matches a {letter} then 0+ {letter|digit|_} -->
  <Keyword name="{word}">{letter}{0+ {letter|digit|_}}</Keyword>

  <!-- {balanced()} matches an opening "(" through (and including) the balancing ")". -->
  <!-- Limitation: at most 4 levels of nesting: (((()))) matches, ((((())))) fails. -->
  <!-- Group #1 matches the stuff *inside* the outermost "(...)". -->
  <Keyword name="{not-{lparen}{rparen}}"      >{not-oneof ()}</Keyword>
  <Keyword name="{balanced{lparen}{rparen}:0}">{0+ {not-()}}</Keyword>
  <Keyword name="{balanced{lparen}{rparen}:1}">{0+ {not-()}|{lparen}{balanced():0}{rparen}}</Keyword>
  <Keyword name="{balanced{lparen}{rparen}:2}">{0+ {not-()}|{lparen}{balanced():1}{rparen}}</Keyword>
  <Keyword name="{balanced{lparen}{rparen}:3}">{0+ {not-()}|{lparen}{balanced():2}{rparen}}</Keyword>
  <Keyword name="{balanced{lparen}{rparen}}"   >{lparen}({balanced():3}){rparen}</Keyword>

  <!-- {unsigned} matches an unsigned integer: one-or-more digits. -->
  <Keyword name="{unsigned}">{digits}</Keyword>

  <!-- {integer} matches an integer: an optional sign plus one-or-more digits. -->
  <Keyword name="{integer}">{optional-sign}{digits}</Keyword>

  <!-- {float} matches a floating point number: optional-sign, digits w/ optional '.', optional-exponent. -->
  <Keyword name="{floatExponent}">{oneof eE}{optional-sign}{digits}</Keyword>
  <Keyword name="{floatMantissa}">{digits}{optional .}{optional-digits}|.{digits}</Keyword>
  <Keyword name="{float}"        >{optional-sign}{floatMantissa}{optional-floatExponent}</Keyword>

  <Keyword name="{minute}">minutes|minute|min</Keyword>
  <Keyword name="{hour}">hours|hour|hrs|hr</Keyword>
  <Keyword name="{sec}">seconds|second|sec</Keyword>
  <Keyword name="{day}">days|day</Keyword>
  <Keyword name="{week}">weeks|week</Keyword>
  <Keyword name="{weekday}">monday|mon|tuesday|tue|wednesday|wed|thursday|thu|friday|fri|saturday|sat|sunday|sun</Keyword>
  <Keyword name="{shorttimetype}">{sec}|{minute}|{hour}|ms</Keyword>
  <Keyword name="{timetype}">{shorttimetype}|{day}</Keyword>
  <Keyword name="{ampm}">AM|am|PM|pm</Keyword>
  <Keyword name="{time}">{1+ {digit}}:{1+ {digit}}{optional :{1+ {digit}}}{optional {ampm}}</Keyword>
  <Keyword name="{splittime}">({1+ {digit}}):({1+ {digit}})({optional :{1+ {digit}}})({optional {ampm}})</Keyword>
  <Keyword name="{freqtype}">every|in</Keyword>
  <Keyword name="{dayweekday}">day|{weekday}</Keyword>
  <Keyword name="{month}">jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec</Keyword>

</PatternConfig>
